﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.IO;

namespace uk.ac.soton.ses.EP2DCDataTypes
{

    /// <summary>
    /// Main REST service to add binary data and create containers in the MDC.
    ///      POST   (Create) 	Create a new resource,
    ///      GET 	(Retrieve)  Retrieve a representation of a resource,
    ///      PUT 	(Update) 	Update a resource,
    ///      DELETE (Delete) 	Delete a resource.
    /// </summary>
    [ServiceContract]
    public interface IEP2DCService
    {

        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "")]
        string HelloWorld();

        /// <summary>
        /// Create a container for a user. Binary objects can be added to the container. 
        /// </summary>
        /// <restMethod>POST</restMethod>
        /// <restTemplate>serviceURL/containers/?id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <returns>A MDCIdentifierMessage: This is the ID for the container, stored in the MDC</returns>
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "containers/?id={userToken}")]
        MDCIdentifierMessage CreateContainer(string userToken);

        /// <summary>
        /// Add a DOI reference to a container. Note this only adds a ref to the DOI 
        /// (from container) and does not import the item: see AddMDCIDToContainer to 
        /// add MDC data to a container. 
        /// </summary>
        /// <restMethod>POST</restMethod>
        /// <restTemplate>serviceURL/containers/{MDCcontainerID}/links?uri={uri}&amp;id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <param name="MDCcontainerID">MDC container ID</param>
        /// <param name="uri">URI to link to container</param>
        /// <returns>A MDCIdentifierMessage: This is a the ID for the new object stored in the MDC</returns>
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "containers/{MDCcontainerID}/links?uri={uri}&id={userToken}")]
        MDCIdentifierMessage AddUriToContainer(string userToken, string MDCcontainerID, string uri);

        /// <summary>
        /// Add a deposited item to a container. eg put an uploaded binary object 
        /// in a container using the MDC IDs
        /// </summary>
        /// <restMethod>POST</restMethod>
        /// <restTemplate>serviceURL/containers/{MDCcontainerID}/linkedobjects?mdcid={mdcid}&amp;id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <param name="MDCcontainerID">MDC container ID</param>
        /// <param name="mdcid">MDC data item ID, e.g. the binary file ID</param>
        /// <returns>A MDCIdentifierMessage: This is a the ID for the new object stored in the MDC</returns>
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "containers/{MDCcontainerID}/linkedobjects?mdcid={mdcid}&id={userToken}")]
        MDCIdentifierMessage AddMDCIDToContainer(string userToken, string MDCcontainerID, string mdcid);

        /// <summary>
        /// Upload binary file 
        /// </summary>
        /// <restMethod>POST</restMethod>
        /// <restTemplate>serviceURL/containers/{MDCcontainerID}/objects?fn={fileName}&amp;length={length}&amp;validateXML={validateXML}&amp;id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <param name="MDCcontainerID">MDC container ID</param>
        /// <param name="fileStream">Memory stream/File Stream etc</param>
        /// <param name="fileName">MDC file name</param>
        /// <param name="length">Long file.length</param>
        /// <param name="validateXML">Whether to automatically validate the XML file against its schema before storing.</param>
        /// <returns>A MDCIdentifierMessage: This is a the ID for the new object stored in the MDC</returns>
        [OperationContract]
        [WebInvoke(Method = "POST", 
            BodyStyle=WebMessageBodyStyle.Bare,
            UriTemplate = "containers/{MDCcontainerID}/objects?fn={fileName}&length={length}&validateXML={validateXML}&id={userToken}")]
        MDCIdentifierMessage UploadFile(string userToken, string MDCcontainerID, Stream fileStream, string fileName, long length, bool validateXML);

        /// <summary>
        /// Returns a list of all MDC binary data ID's for a given container
        /// </summary>        
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL/containers/{MDCcontainerID}/?id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <param name="MDCcontainerID">MDC container ID</param>
        /// <returns>A MDCIdentifierMessage: This is a the ID for the objects stored in the MDC</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "containers/{MDCcontainerID}/?id={userToken}")]
        MDCIdentifierMessage GetMDCIDsInContainer(string userToken, string MDCcontainerID);


        /// <summary>
        /// Delete a container. NOTE, this is NOT implemented
        /// </summary>
        /// <restMethod>DELETE</restMethod>
        /// <restTemplate>serviceURL/containers/{MDCcontainerID}/?id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <param name="MDCcontainerID"></param>
        /// <returns>ACKMsg : indicating isSucessful</returns>
        [OperationContract]
        [WebInvoke(Method = "DELETE", UriTemplate = "containers/{MDCcontainerID}/?id={userToken}")]
        ACKMsg DeleteContainer(string userToken, string MDCcontainerID);

        /// <summary>
        /// Get a list of XML types, this is a list of XSD schema names, so the MDC 
        /// can validate the data.  NOTE, this is NOT implemented      
        /// </summary>
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL?id={userToken}</restTemplate>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <returns>List of data types</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "?id={userToken}")]
        DataTypeMsg ListDataTypes(string userToken);
        

        /// <summary>
        /// Get the time at the server.Handy for testing. 
        /// </summary>
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL/time</restTemplate>
        /// <returns>A DateTime object</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "time")]
        DateTime GetServerTime();


        /// <summary>
        /// Given an MDC id, this will return the URI to that item, both containers and files.
        /// </summary>
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL/allitems/{MDCID}/uri?id={userToken}</restTemplate>
        /// <param name="MDCID">MDC file ID</param>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <returns>A URI for the given MDC ID</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "allitems/{MDCID}/uri?id={userToken}")]
        URIMsg GetURIForMDCID(string userToken, string MDCID);


        /// <summary>
        /// Given a path, this will return the MDCID of that item, both containers and files if it exists.
        /// </summary>
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL/getmdcid/?object={objectPath}&amp;id={userToken}</restTemplate>
        /// <param name="objectPath">MDC file path</param>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <returns>An MDC ID for the given path</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "getmdcid/?object={objectPath}&id={userToken}")]
        MDCIdentifierMessage GetMDCIDForObjectPath(string userToken, string objectPath);


        /// <summary>
        /// Given an MDC id this will return an iFrame (as a string) which can be embedded into 
        /// a 3rd party website/page. NOTE we will need to decide on the size. 
        /// This will be useds to provide feedback on files/containers.
        /// </summary>
        /// <restMethod>GET</restMethod>
        /// <restTemplate>serviceURL/allitems/{MDCID}/info/html?id={userToken}</restTemplate>
        /// <param name="MDCID">MDC file ID</param>
        /// <param name="userToken">User ID token e.g. Shibboleth token user name</param>
        /// <returns>A message containing HTML for displaying elsewhere</returns>
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "allitems/{MDCID}/info/html?id={userToken}")]
        MDCHTMLMessage GetHTMLForMDCID(string userToken, string MDCID);
    }


    [DataContract]
    public class ACKMsg
    {
        [DataMember]
        public bool isSuccessful
        {
            get;
            set;
        }

        [DataMember]
        public MDCErrorMessage errorMessage { get; set; }
    }


    [DataContract]
    public class URIMsg
    {
        [DataMember]
        public Uri uri
        {
            get;
            set;
        }

        [DataMember]
        public String displayText
        {
            get;
            set;
        }

        [DataMember]
        public MDCErrorMessage errorMessage { get; set; }
    }


    [DataContract]
    public class MDCErrorMessage
    {
        [DataMember]
        public String displayErrorMsg
        {
            get;
            set;
        }

        [DataMember]
        public String fullError
        {
            get;
            set;
        }
    }

    [DataContract]
    public class MDCIdentifierMessage
    {
        private List<string> _MDCids = new List<string>();
        [DataMember]
        public List<string> MDCIds
        {
            get { return _MDCids; }
            set { _MDCids = value; }
        }

        [DataMember]
        public MDCErrorMessage errorMessage { get; set; }
        
    }
    [DataContract]
    public class MDCHTMLMessage
    {
        [DataMember]
        public string Html { get; set; }
        [DataMember]
        public MDCErrorMessage errorMessage { get; set; }
    }

    [DataContract]
    public class DataTypeMsg
    {
        private List<DataTypeMember> _DataTypes = new List<DataTypeMember>();

        [DataMember]
        public List<DataTypeMember> DataTypes
        {
            get { return _DataTypes; }
            set { _DataTypes = value; }
        }

        [DataMember]
        public MDCErrorMessage errorMessage { get; set; }
    }

    [DataContract]
    public class DataTypeMember
    {
        [DataMember]
        public string Id { get; set; }
        [DataMember]
        public string DisplayText { get; set; }
    }




    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}
